/**
 * @file watermark.js 水印插件
 * @author lisfan {@link http://mailto:448182355@qq.com|448182355@qq.com} {@link https://github.com/lisfan|GIT@lisfan}
 * @version 0.0.1
 * @license MIT
 * @description 
 * 
 * ## **说明 Desc**
 * 
 * 包含多种增加水印方式，支持配置自定义参数
 * 
 * 1. 文本水印
 * 2. 图片水印（未实现）
 * 
 * ## **注意 Tips**
 * 
 * 标准浏览器支持良好，IE10以下浏览器会有些不可预知问题，未详细测试
 * 
 * 目前已知的问题：
 * 1. IE9会有黑底切裁断问题：应该是css3支持力度差，且filter私有样式也不再支持
 * 2. 由于文本水印是基于dom实现的，会受用户的系统环境和系统字体以及用户强制自定义样式的影响而有差异
 * 3. IE下只支持少部分的options配置
 *
 * ## **更新日志 Update Log**
 * 
 * ### 0.0.1
 * 
 * #### 2016/06/12
 *   - 基础构建
 * 
 * 
 * #### 2016/06/15
 *   - [bug fix] 修复了 IE下受某些默认字体的影响造成的文字不一致问题，强制设置为宋体
 *   
 * @todo 
 * 
 * Todo List
 * - 图片水印方式
 * 
 * @example 水印文字
 * 
 * // 水印内容直接使用字符串，适合简短的内容或者不需要排版的内容
 * // 具体配置参数见$option @see $options   
 *     
 *     new Watermark({
 *           el: '#table',
 *           content: '我是水印内容' 
 *       });
 *       
 * @example 水印dom内容
 *          
 * // 引用整个 DOM 节点格式
 * 
 *      new Watermark({
 *           el: '#table',
 *           content: '#select'
 *       });
 */

(function (factory) {
    'use strict';

    // 若存在模块加载器，则定义为一个模块
    if (typeof window.define === 'function' && (window.define.amd || window.define.cmd)) {
        window.define(['util'], factory);
    }

    // 注入到 全局对象
    if (typeof window.Watermark === 'undefined') {
        window.Watermark = factory(window.util);
    } else {
        throw new Error('存在同名的Watermark库');
    }
}(function (util) {
    'use strict';

    /**
     * 设置全局配置参数：会作用于全部，生成实例时都会使用 全局默认配置覆盖实例默认配置，具体配置参数内容见 $options
     * @member {Object} config
     * @memberof Watermark
     * @since 0.0.1
     * @static
     */
    Watermark.config = {};

    /**
     * 构造函数   
     * @class Watermark 
     * @param {Object} [options] - 水印配置参数，具体见 {@link $options}
     */
    function Watermark(options) {
        /**
         * @instance
         * @memberof Watermark
         * @since 0.0.1
         * @member {Object} $options
         * @property {String|Selector|Element} el=document.body - 附加水印的目标节点DOM 
         * @property {String|Selector|Element} content='请设置水印内容'  - 水印内容，注：如果是 IE9 以下，选择器使用id方式，标准浏览器可以使用class
         * @property {Number} type=1 - 水印类型，可选值：1（文字水印），2（图片水印）
         * @property {String} repeat=xy - 水印平辅方式，可选值：x（水平平辅），y（垂直平辅），##xy（水平与垂直平辅）##
         * @property {String} elClass='ext-watermark' - 水印外包裹dom 样式命名空间
         * @property {String} contentClass='ext-watermark-content' - 水印dom 样式命名空间
         * @property {Number} zIndex=0 - 水印包裹器的堆叠层级
         * @property {String} bgColor='#fff' - 水印包裹器的背景颜色
         * @property {Number} opacity=1 - 水印包裹器的透明度，范围为0-1
         * @property {String} width='auto' - 水印内容的宽度，可以使用任意单位
         * @property {String} height='auto' - 水印内容的高度，可以使用任意单位
         * @property {String} padding='0px 300px 100px 300px' - 水印内容的内边距，可以使用任意单位
         * @property {String} margin='auto' - 水印内容的外边距，可以使用任意单位
         * @property {Number} rotate=346 - 水印旋转角度
         * @property {String} color='#e4e4e4' - 水印颜色
         * @property {String} fontSize='30px' - 水印内容字号，可以使用任意单位
         * @property {String} fontFamily='simsun' - 水印内容字体样式
         * @property {String} lineHeight='2' - 水印内容行高，可以使用任意单位
         */
        this.$options = {
            el: document.body,
            content: '请设置水印内容',
            type: 1,
            repeat: 'xy',
            elClass: 'ext-watermark',
            contentClass: 'ext-watermark-content',

            //offset: '0 0', //水印包裹器的起始位置：相对于目标el的定位父元素，默认‘0 0’第一个数代表水平方向，第二个数代表垂直方向
            zIndex: 0,
            bgColor: '#fff',
            opacity: 1,

            width: 'auto', //水印块的宽度，默认自动
            height: 'auto', //水印块的高度，默认自动
            padding: '0px 300px 100px 300px', //水印块的内边距
            margin: 'auto', //水印块的外边距

            rotate: 346,
            color: '#e4e4e4', //水印块的文本颜色，默认#e4e4e4;
            fontSize: '30px',
            fontFamily: 'simsun',
            lineHeight: '2'
        };

        // 使用全局配置覆盖默认配置
        util.extend(this.$options, Watermark.config, true);

        // 使用自定义配置
        util.extend(this.$options, options, true);

        // 存在options.content 参数时，直接初始化
        if (!util.isUndefined(options.content)) {
            this.load(options);
        }
    }

    /**
     * 载入水印内容
     * @param {String|Selector|Element} content  水印内容：可以是一个字符串、也可以是一个简易选择器字符串，或者是一个 DOM 节点
     * @instance
     * @memberof Watermark
     * @function
     * @since 0.0.1
     */
    Watermark.prototype.load = function (content) {
        // 清空
        _private.__clean__.call(this);

        // valide
        if (util.isString(content) || util.isElement(content)) {
            this.$options.content = content;
        }

        _private.__renderDom__.call(this);
    }

    /**
     * 显示水印
     * @instance
     * @memberof Watermark
     * @function
     * @since 0.0.1
     */
    Watermark.prototype.show = function (delay) {
        util.show(this.$el);
    };

    /**
     * 隐藏水印
     * @instance
     * @memberof Watermark
     * @function
     * @since 0.0.1
     */
    Watermark.prototype.hide = function () {
        util.hide(this.$el);
    };

    /**
     * 清空实例对象 DOM 
     * @instance
     * @memberof Watermark
     * @function
     * @since 0.0.1
     */
    Watermark.prototype.clean = function () {
        _private.__clean__.call(this);
    };

    /**
     * 销毁实例对象
     * @instance
     * @memberof Watermark
     * @function
     * @since 0.0.1
     */
    Watermark.prototype.destory = function () {
        util.remove(this.$el);
    };


    // 私有
    var _private = {
        /**
         * 清空实例 DOM
         * @this Watermark
         * @ignore
         */
        __clean__: function () {
            if (this.$el) {
                this.$el.innerHTML = '';
            }
        },
        /**
         * 渲染实例 DOM
         * @this Watermark
         * @ignore
         */
        __renderDom__: function () {
            // valide content
            if (!(util.isString(this.$options.content) || util.isElement(this.$options.content))) {
                throw new Error('$options.content 必须是一个字符串、也可以是一个简易选择器字符串，或者是一个 DOM 节点');
            }

            // valide el
            if (!(util.isString(this.$options.el) || util.isElement(this.$options.el))) {
                throw new Error('$options.el 必须是是一个简易选择器字符串，或者是一个 DOM 节点');
            }

            // 最外层包裹器
            if (!this.$wrapper) {
                this.$wrapper = util.createElement('div');
            }

            // 创建水印最外层包裹器节点
            if (!this.$target) {
                this.$target = util.$(this.$options.el);
                util.insertBefore(this.$target, this.$wrapper);
                util.appendChild(this.$wrapper, this.$target);
            }

            // 为目标节点创建一个父节点，包裹目标节点和水印节点，并提升目标节点的层级
            util.extend(this.$target.style, {
                position: 'relative',
                zIndex: this.$options.zIndex + 10
            });

            util.extend(this.$wrapper.style, {
                position: 'relative',
                overflow: 'hidden',
                width: this.$target.clientWidth + 'px',
                heigth: this.$target.clientHeight + 'px'
            });

            // 创建 水印 DOM 的基础结构
            if (!this.$el) {
                this.$el = util.createElement('div');
                util.appendChild(this.$wrapper, this.$el);
            }

            util.extend(this.$el.style, {
                position: 'absolute',
                left: 0,
                right: 0,
                top: 0,
                bottom: 0,
                zIndex: this.$options.zIndex,
                opacity: this.$options.opacity,
                backgroundColor: this.$options.bgColor,
                userSelect: 'none',
                webkitUserSelect: 'none',
                mozUserSelect: 'none',
                msUserSelect: 'none',
                oUserSelect: 'none'
            }, true);

            // 根据content的配置，设置内容
            var elContent;

            if (util.isElement(this.$options.content)) {
                elContent = util.$(this.$options.content);
            } else if (util.isString(this.$options.content)) {
                //为选择器或字符串时
                elContent = util.$(this.$options.content);
                if (util.isCollection(elContent)) {
                    elContent = elContent[0];
                } else if (!util.isElement(elContent)) {
                    elContent = util.createElement('div');
                    elContent.innerHTML = this.$options.content;
                }
            }

            // 附加样式
            elContent.className = this.$options.contentClass;


            // 不支持CSS3的IE10以下浏览器特珠处理
            var degree = 14;
            var formula = (180 - degree) * Math.PI / 180;
            var asin = Math.sin(formula);
            var acos = Math.cos(formula);

            // 设置水印样式
            util.extend(elContent.style, {
                position: 'absolute',
                left: 0,
                top: 0,
                display: 'inline-block',
                width: this.$options.width,
                height: this.$options.height,
                padding: this.$options.padding,
                margin: this.$options.margin,
                color: this.$options.color,
                fontSize: this.$options.fontSize,
                lineHeight: this.$options.lineHeight,
                transform: 'rotate(' + this.$options.rotate + 'deg)',
                webkitTransform: 'rotate(' + this.$options.rotate + 'deg)',
                mozTransform: 'rotate(' + this.$options.rotate + 'deg)',
                msTransform: 'rotate(' + this.$options.rotate + 'deg)',
                oTransform: 'rotate(' + this.$options.rotate + 'deg)',
                zoom: 1,
                whiteSpace: 'nowrap',
                msFilter: 'progid:DXImageTransform.Microsoft.Matrix(M11=' + (-acos) + ',M12=' + (asin) + ',M21=' + (-asin) + ',M22=' + (-acos) + ',SizingMethod="auto expand"', // 不支持CSS3的IE10以下浏览器特珠处理
                filter: 'progid:DXImageTransform.Microsoft.Matrix(M11=' + (-acos) + ',M12=' + (asin) + ',M21=' + (-asin) + ',M22=' + (-acos) + ',SizingMethod="auto expand")' // 不支持CSS3的IE10以下浏览器特珠处理
            }, true);

            util.appendChild(this.$el, elContent);

            // 重置主样式
            this.$el.className = this.$options.elClass;

            util.show(elContent);

            // 根据平辅配置，平辅水印，求得可平辅数量
            if (util.isString(this.$options.repeat)) {
                // 取得数量
                var targetWidth = this.$target.clientWidth;
                var targetHeight = this.$target.clientHeight;
                var contentWidth = elContent.clientWidth;
                var contentHeight = elContent.clientHeight;
                var repeatXCount = Math.ceil(targetWidth / contentWidth);
                var repeatYCount = Math.ceil(targetHeight / contentHeight);
                var repeatXFlag = this.$options.repeat.indexOf('x') >= 0 ? true : false;
                var repeatYFlag = this.$options.repeat.indexOf('y') >= 0 ? true : false;

                // 移除首个content
                util.remove(elContent);

                // 平辅方式
                if (repeatXFlag && repeatYFlag) {
                    // 水平且垂直平辅
                    for (var i = 0; i < repeatXCount; i++) {
                        for (var j = 0; j < repeatYCount; j++) {
                            var $cloneNode = util.clone(elContent);
                            $cloneNode.style.left = i * contentWidth + 'px';
                            $cloneNode.style.top = j * contentHeight + 'px';
                            util.appendChild(this.$el, $cloneNode);
                            unSelectText($cloneNode);
                        }
                    }
                } else if (repeatXFlag) {
                    // 水平平辅
                    for (var i = 0; i < repeatXCount; i++) {
                        var $cloneNode = util.clone(elContent);
                        $cloneNode.style.left = i * contentWidth + 'px';
                        util.appendChild(this.$el, $cloneNode);
                        unSelectText($cloneNode);
                    }
                } else if (repeatYFlag) {
                    // 垂直平辅
                    for (var j = 0; j < repeatYCount; j++) {
                        var $cloneNode = util.clone(elContent);
                        $cloneNode.style.top = j * contentHeight + 'px';
                        util.appendChild(this.$el, $cloneNode);
                        unSelectText($cloneNode);
                    }
                }

                // 不可选中文本
                function unSelectText(ele) {
                    if (!util.isUndefined(ele['onselectstart'])) {
                        ele.onselectstart = function () {
                            return false;
                        }
                    }

                    if (!util.isUndefined(ele['ondrag'])) {
                        ele.ondrag = function () {
                            return false;
                        }
                    }
                }
            }

            util.show(this);
        }
    }

    return Watermark;
}));